#include "analyzer.hpp"


analyzer::analyzer(const string& file)
:	ast_root(NULL), cfg_root(NULL), flat(NULL), rd(NULL), lv(NULL), ds(NULL), iv(NULL)
{
	antlr_wrapper while_parser(file);
	this->ast_root = while_parser.run();
}

void analyzer::print_AST(const string& dot_file) {
	ASTvisitorDOT dot;
	dot.StartVisit(this->ast_root);
	dot.writeDOTfile(dot_file.c_str());
}

void analyzer::print_CFG(const string& dot_file) {
	this->ensure_cfg_exists();

	CFGvisitorDOT dot;
	dot.StartVisit(this->cfg_root);
	dot.writeDOTfile(dot_file.c_str());
}

void analyzer::ensure_RD_has_run() {
	if (this->rd) return;
	this->ensure_flatinfo_exists();
	
	this->rd = new ReachingDefs(this->flat);
	this->rd->run();
}

void analyzer::ensure_LV_has_run() {
	if (this->lv) return;
	this->ensure_flatinfo_exists();
	
	this->lv = new LiveVariable(this->flat);
	this->lv->run();
}

void analyzer::ensure_DS_has_run() {
	if (this->ds) return;
	this->ensure_flatinfo_exists();
	
	this->ds = new DetectionSign(this->flat, this->ast_root);
	this->ds->run();
}

void analyzer::ensure_IV_has_run() {
	if (this->iv) return;
	this->ensure_flatinfo_exists();
	
	this->iv = new IntervalAnalysis(this->flat, this->ast_root);
	this->iv->run();
}

void analyzer::print_RD_analysis() {
	this->ensure_RD_has_run();
	this->rd->report("RD");
}

void analyzer::print_LV_analysis() {
	this->ensure_LV_has_run();
	this->lv->report("LV");
}

void analyzer::print_DS_analysis() {
	this->ensure_DS_has_run();
	this->ds->report("DS");
}

void analyzer::print_IV_analysis() {
	this->ensure_IV_has_run();
	this->iv->report("IV");
}

void analyzer::ensure_cfg_exists() {
	if (this->cfg_root) return; // If CFG has been created already, don't create it again
	
	assert(this->ast_root);
	ASTvisitorCFG c;
	this->cfg_root = c.convert(this->ast_root);
}

void analyzer::ensure_flatinfo_exists() {
	if (this->flat) return;

	this->ensure_cfg_exists();
	this->flat = new CFGvisitorFlatInfo();
	this->flat->StartVisit(this->cfg_root);
}

void analyzer::print_program_slice(label_t poi) {
	this->ensure_RD_has_run();
	this->ensure_flatinfo_exists();
	
	const int max_label = this->flat->labels.size()-1; // make zero-indexed
	const bool okay = ((poi >= 0)&&(poi <= max_label));
	if (!okay) {
		cerr << "Poi must be between 0 and " << max_label << " (both inclusive)." << endl;
		return;
	}

	program_slicing p(*(this->flat), *(this->rd));
	p.pslice(poi);
	cout << "pslice(poi=" << poi << ") = " << p.getS() << endl;
}

void analyzer::print_dead_code() {
	this->ensure_LV_has_run();
	this->ensure_flatinfo_exists();
	
	dead_code d(*(this->flat), *(this->lv));
	cout << "dead = " << d.dead() << endl;
}

void analyzer::print_underflow() {
	this->ensure_DS_has_run();
	this->ensure_flatinfo_exists();
	
	buffer_underflow uf(*(this->flat), *(this->ds));
	cout << "underflow = " << uf.underflow() << endl;
}

void analyzer::print_overunderflow() {
	this->ensure_IV_has_run();
	this->ensure_flatinfo_exists();
	
	buffer_outofbounds uf(*(this->flat), *(this->iv));
	cout << "overunderflow = " << uf.out_of_bounds() << endl;
}
